package org.baicaixiaozhan.springbootwebdemo1.annotation.aspectj;

import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.baicaixiaozhan.springbootwebdemo1.annotation.PreAuthorize;
import org.baicaixiaozhan.springbootwebdemo1.exception.NoAccessPermissionException;
import org.baicaixiaozhan.springbootwebdemo1.security.SecurityExpressionOperations;
import org.baicaixiaozhan.springbootwebdemo1.util.HttpUtils;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * DESC:
 *
 * @author : baicaixiaozhan
 * @since : 2021-01-31
 */
@Aspect
@Component
@Slf4j
public class PreAuthorizeAspect {

    /**
     * SpEL 表达式解析器
     */
    private static final SpelExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();

    /**
     * 在调用方法之前, 校验当前登录用户是否有访问该方法的角色和权限
     *
     * @param proceedingJoinPoint
     */
    @Around(value = "@annotation(org.baicaixiaozhan.springbootwebdemo1.annotation.PreAuthorize)")
    public Object beforeInvokeMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // Method Information
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();
        PreAuthorize annotation = method.getAnnotation(PreAuthorize.class);
        Object object = null;
        if (annotation.roles().length != 0) {
            object = processorParameterNameInRoles(annotation.roles(), proceedingJoinPoint);
        }
        if (!Strings.isNullOrEmpty(annotation.value())) {
            object = processorParameterNameInValue(annotation.value(), proceedingJoinPoint);
        }
        return object;
    }

    private Object processorParameterNameInRoles(String[] roles, ProceedingJoinPoint proceedingJoinPoint)
            throws Throwable {
        Set<String> roleSet = Arrays.stream(roles).collect(Collectors.toUnmodifiableSet());
        String permission = HttpUtils.getCurrentLoginUser().getUserRole().name();
        if (roleSet.contains(permission)) {
            return proceedingJoinPoint.proceed();
        }
        throw new NoAccessPermissionException("没有权限");
    }

    private Object processorParameterNameInValue(String value, ProceedingJoinPoint proceedingJoinPoint)
            throws Throwable {
        EvaluationContext context = new StandardEvaluationContext();
        Expression sun = EXPRESSION_PARSER.parseExpression("1+1");
        log.info("sun : {}",sun.getValue(Integer.class));
        Expression expression = EXPRESSION_PARSER.parseExpression("#operations." + value);
        context.setVariable("operations", new SecurityExpressionOperations());
        if (expression.getValue(context, Boolean.class)) {
            return proceedingJoinPoint.proceed();
        }
        throw new NoAccessPermissionException("没有权限");
    }
}
